package cn.iocoder.yudao.module.wms.service.rdrecord32;

import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.wms.controller.admin.productionorder.vo.ProductionOrderSaveReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.productionorder.vo.ProductionOrdersRespVO;
import cn.iocoder.yudao.module.wms.controller.admin.rdrecord10.vo.Rdrecords10RespVO;
import cn.iocoder.yudao.module.wms.controller.admin.saleorder.vo.SaleDetialRespVO;
import cn.iocoder.yudao.module.wms.controller.admin.saleorder.vo.SaleOrderSaveReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.stock.vo.StockLogRespVO;
import cn.iocoder.yudao.module.wms.controller.admin.stock.vo.StockRespVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.productionorder.ProductionOrderDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.rdrecord10.Rdrecord10DO;
import cn.iocoder.yudao.module.wms.dal.dataobject.rdrecord10.Rdrecords10DO;
import cn.iocoder.yudao.module.wms.dal.dataobject.saleorder.SaleOrderDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.stock.StockDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.stock.StockLogDO;
import cn.iocoder.yudao.module.wms.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.wms.dal.redis.serialNumber.WmsSerialNumberRedisDAO;
import cn.iocoder.yudao.module.wms.service.saleorder.SaleOrderService;
import cn.iocoder.yudao.module.wms.service.stock.StockService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import cn.iocoder.yudao.module.wms.controller.admin.rdrecord32.vo.*;
import cn.iocoder.yudao.module.wms.dal.dataobject.rdrecord32.Rdrecord32DO;
import cn.iocoder.yudao.module.wms.dal.dataobject.rdrecords32.Rdrecords32DO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.wms.dal.mysql.rdrecord32.Rdrecord32Mapper;
import cn.iocoder.yudao.module.wms.dal.mysql.rdrecords32.Rdrecords32Mapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;

/**
 * 销售出库主 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class Rdrecord32ServiceImpl implements Rdrecord32Service {
    public static final String PROCESS_KEY = "rdrecord32";
    @Resource
    private WmsSerialNumberRedisDAO serialNumberRedisDAO;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Resource
    private Rdrecord32Mapper rdrecord32Mapper;
    @Resource
    private Rdrecords32Mapper rdrecords32Mapper;

    @Resource
    private StockService stockService;

    @Resource
    private SaleOrderService saleOrderService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createRdrecord32(Rdrecord32SaveReqVO createReqVO) {
        // 插入
        String serialNumber = serialNumberRedisDAO.generate(WmsSerialNumberRedisDAO.POMAIN_SERIAL_PREFIX, RedisKeyConstants.SERIALBOM);

        Rdrecord32DO rdrecord32 = BeanUtils.toBean(createReqVO, Rdrecord32DO.class) .setStatus(BpmTaskStatusEnum.SUBMIT.getStatus()).setSerialNumber(serialNumber);
        rdrecord32Mapper.insert(rdrecord32);

        // 插入子表
        createRdrecords32List(rdrecord32.getId(), createReqVO.getRdrecords32s());

        //执行出库操作
        businessProcessing(createReqVO,createReqVO.getRdrecords32s());

        // 返回
        return rdrecord32.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRdrecord32(Rdrecord32SaveReqVO updateReqVO) {
        // 校验存在
        validateRdrecord32Exists(updateReqVO.getId());
        //获取旧数据
        List<Rdrecords32DO> oldList=rdrecords32Mapper.selectListByPid(updateReqVO.getId());
        Rdrecord32DO oldRdrecord32DO=getRdrecord32(updateReqVO.getId());

        Rdrecord32DO updateObj = BeanUtils.toBean(updateReqVO, Rdrecord32DO.class);

        //旧数据 恢复
        if (oldList!=null) {
            //恢复销售单数量 恢复库存数量
            for (Rdrecords32DO rdrecords32DO : oldList) {
                //子表通过stockId查询对应的存货档案
                StockRespVO stockDOMain = stockService.getStock(rdrecords32DO.getStockId());
                //获取销售订单子表对应出库的信息
                SaleDetialRespVO saleDetialRespVO = saleOrderService.findSaleDetialByInventoryIdAndPid(stockDOMain.getInventoryId(), oldRdrecord32DO.getSaleOrderId());
                saleDetialRespVO.setOutQty(saleDetialRespVO.getOutQty() - rdrecords32DO.getQuantity());
                saleOrderService.updateSaleDetial(saleDetialRespVO);
                //修改销售订单的主表数量
                SaleOrderDO saleOrderDO = saleOrderService.getSaleOrder(saleDetialRespVO.getPid());
                saleOrderDO.setOutNumber(saleOrderDO.getOutNumber() - rdrecords32DO.getQuantity());
                SaleOrderSaveReqVO saleOrderSaveReqVO = new SaleOrderSaveReqVO();
                BeanUtils.copyProperties(saleOrderDO, saleOrderSaveReqVO);
                saleOrderService.updateSaleOrder(saleOrderSaveReqVO);

                //恢复库存数量
                StockDO stockDO=new StockDO().setQty(rdrecords32DO.getQuantity()).setInventoryId(saleDetialRespVO.getInventoryId())
                        .setWarehouseId(oldRdrecord32DO.getWarehouseId()).setLocationId(rdrecords32DO.getLocationId()).setBatchCode(rdrecords32DO.getBatchCode());
                stockService.restoreRK(stockDO);
            }
        }

       //执行出库操作
        businessProcessing(updateReqVO,updateReqVO.getRdrecords32s());


        // 更新
        rdrecord32Mapper.updateById(updateObj);
        // 更新子表
        updateRdrecords32List(updateReqVO.getId(), updateReqVO.getRdrecords32s());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRdrecord32(Integer id) {
        // 校验存在
        validateRdrecord32Exists(id);
        // 删除
        Rdrecord32DO rdrecord32DO=rdrecord32Mapper.selectById(id);
        List<Rdrecords32DO> oldList=rdrecords32Mapper.selectListByPid(id);



        if (oldList!=null) {
            //恢复销售单数量
            for (Rdrecords32DO rdrecords32DO : oldList) {
                //子表通过stockId查询对应的存货档案
                StockRespVO stockDOMain = stockService.getStock(rdrecords32DO.getStockId());
                //获取销售订单子表对应出库的信息
                SaleDetialRespVO saleDetialRespVO = saleOrderService.findSaleDetialByInventoryIdAndPid(stockDOMain.getInventoryId(), rdrecord32DO.getSaleOrderId());
                saleDetialRespVO.setOutQty(saleDetialRespVO.getOutQty() - rdrecords32DO.getQuantity());
                saleOrderService.updateSaleDetial(saleDetialRespVO);
                //修改销售订单的主表数量
                SaleOrderDO saleOrderDO = saleOrderService.getSaleOrder(saleDetialRespVO.getPid());
                saleOrderDO.setOutNumber(saleOrderDO.getOutNumber() - rdrecords32DO.getQuantity());
                SaleOrderSaveReqVO saleOrderSaveReqVO = new SaleOrderSaveReqVO();
                BeanUtils.copyProperties(saleOrderDO, saleOrderSaveReqVO);
                saleOrderService.updateSaleOrder(saleOrderSaveReqVO);

                //恢复库存数量
                StockDO stockDO=new StockDO().setQty(rdrecords32DO.getQuantity()).setInventoryId(saleDetialRespVO.getInventoryId())
                        .setWarehouseId(rdrecord32DO.getWarehouseId()).setLocationId(rdrecords32DO.getLocationId()).setBatchCode(rdrecords32DO.getBatchCode());
                stockService.restoreRK(stockDO);

            }
        }

        rdrecord32Mapper.deleteById(id);
        // 删除子表
        deleteRdrecords32ByPid(id);
    }

    private void validateRdrecord32Exists(Integer id) {
        if (rdrecord32Mapper.selectById(id) == null) {
            throw exception(RDRECORD32_NOT_EXISTS);
        }
    }

    @Override
    public Rdrecord32DO getRdrecord32(Integer id) {
        return rdrecord32Mapper.selectById(id);
    }

    @Override
    public PageResult<Rdrecord32DO> getRdrecord32Page(Rdrecord32PageReqVO pageReqVO) {
        return rdrecord32Mapper.selectPage(pageReqVO);
    }

    // ==================== 子表（销售出库子） ====================

    @Override
    public List<Rdrecords32DO> getRdrecords32ListByPid(Integer pid) {
        return rdrecords32Mapper.selectListByPid(pid);
    }

    @Override
    public void updateRdrecord32Status(Rdrecord32SaveReqVO reqVO) {
        rdrecord32Mapper.updateRdrecord32Status(reqVO);
    }

    @Override
    public Rdrecord32DO findByProcessInstanceId(String processInstanceId) {
        return rdrecord32Mapper.findByProcessInstanceId(processInstanceId);
    }

    @Override
    public int findCountByCode(String code) {
        return rdrecord32Mapper.findCountByCode(code);
    }

    @Override
    public List<Rdrecords10RespVO> findRdrecords32ByPid(Integer pid) {
        return rdrecord32Mapper.findRdrecords32ByPid(pid);
    }

    /***
     * 备忘录
     * 子表通过stockLogId查询对应的存货档案
     * @param rdrecord32DO
     * @param rdrecords32DOList
     */
    public void businessProcessing(Rdrecord32SaveReqVO rdrecord32DO, List<Rdrecords32DO> rdrecords32DOList) {
        //销售出库
        for(Rdrecords32DO rdrecords32DO:rdrecords32DOList)
        {
            //子表通过stockId查询对应的存货档案
            StockRespVO stockDOMain=stockService.getStock(rdrecords32DO.getStockId());
            //获取销售订单子表对应出库的信息
            SaleDetialRespVO saleDetialRespVO=saleOrderService.findSaleDetialByInventoryIdAndPid(stockDOMain.getInventoryId(),rdrecord32DO.getSaleOrderId());
            if ((saleDetialRespVO.getQty()-saleDetialRespVO.getOutQty())>=rdrecords32DO.getQuantity())
            {
                saleDetialRespVO.setOutQty(saleDetialRespVO.getOutQty()+rdrecords32DO.getQuantity());
                saleOrderService.updateSaleDetial(saleDetialRespVO);
                //修改销售订单的主表数量
                SaleOrderDO saleOrderDO=saleOrderService.getSaleOrder(saleDetialRespVO.getPid());
                saleOrderDO.setOutNumber(saleOrderDO.getOutNumber()+rdrecords32DO.getQuantity());
                SaleOrderSaveReqVO saleOrderSaveReqVO=new SaleOrderSaveReqVO();
                BeanUtils.copyProperties(saleOrderDO,saleOrderSaveReqVO);
                saleOrderService.updateSaleOrder(saleOrderSaveReqVO);
            }else {
                throw exception(RDRECORD32_NUMBER_OUT);
            }

            //执行入库方法
            StockDO stockDO=new StockDO().setQty(rdrecords32DO.getQuantity()).setInventoryId(saleDetialRespVO.getInventoryId())
                    .setWarehouseId(rdrecord32DO.getWarehouseId()).setLocationId(rdrecords32DO.getLocationId()).setBatchCode(rdrecords32DO.getBatchCode());
            stockService.Outbound(stockDO);
        }
    }

    @Override
    public void process(Integer id) {
        /***
         * 启动流程
         */

        // 发起 BPM 流程
        Map<String, Object> processInstanceVariables = new HashMap<>();
        String processInstanceId = processInstanceApi.createProcessInstance(SecurityFrameworkUtils.getLoginUserId(),
                new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
                        .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(id)));

        // 将工作流的编号，更新到 业务表单中
        rdrecord32Mapper.updateById(new Rdrecord32DO().setId(id).setProcessInstanceId(processInstanceId).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()));


    }

    private void createRdrecords32List(Integer pid, List<Rdrecords32DO> list) {
        list.forEach(o -> o.setPid(pid));
        rdrecords32Mapper.insertBatch(list);
    }

    private void updateRdrecords32List(Integer pid, List<Rdrecords32DO> list) {
        deleteRdrecords32ByPid(pid);
		list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createRdrecords32List(pid, list);
    }

    private void deleteRdrecords32ByPid(Integer pid) {
        rdrecords32Mapper.deleteByPid(pid);
    }

}